<template>
  <n-button 
    quaternary 
    circle 
    size="small"
    @click="exportChat"
    :loading="exporting"
    :disabled="!canExport">
    <template #icon>
      <n-icon>
        <CloudDownloadOutline />
      </n-icon>
    </template>
  </n-button>
</template>

<script setup lang="ts">
import { NButton, NIcon, useMessage } from 'naive-ui'
import { CloudDownloadOutline } from '@vicons/ionicons5'
import { ref, computed } from 'vue'
import { saveAs } from 'file-saver'
import { Document, Packer, Paragraph, TextRun, AlignmentType, Table, TableRow, TableCell, WidthType, ImageRun } from 'docx'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'

// Props
const props = defineProps({
  messages: { 
    type: Array as () => any[], 
    default: () => [] 
  },
  sessionId: { type: String, default: '' },
  sessionTitle: { type: String, default: '' }
})

// Emits
const emit = defineEmits(['export-start', 'export-success', 'export-error'])

// State
const exporting = ref(false)
const message = useMessage()

// Computed
const canExport = computed(() => props.messages && props.messages.length > 0)

// Markdown解析器
const md = new MarkdownIt({
  html: true,
  highlight: function (str: string, lang: string) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="hljs"><code>${hljs.highlight(str, { language: lang }).value}</code></pre>`
      } catch (__) {}
    }
    return `<pre class="hljs"><code>${md.utils.escapeHtml(str)}</code></pre>`
  }
})

// 导出方法
async function exportChat() {
  if (!canExport.value) {
    message.warning('无可导出内容')
    return
  }

  exporting.value = true
  emit('export-start')

  try {
    const docParagraphs = []
    
    // 添加标题
    docParagraphs.push(
      new Paragraph({
        children: [
          new TextRun({
            text: `聊天记录 - ${props.sessionTitle || props.sessionId}`,
            bold: true,
            size: 24,
            color: '2E86AB'
          })
        ],
        alignment: AlignmentType.CENTER,
        spacing: { after: 400 }
      })
    )

    // 添加导出时间
    docParagraphs.push(
      new Paragraph({
        children: [
          new TextRun({
            text: `导出时间: ${new Date().toLocaleString('zh-CN')}`,
            size: 12,
            color: '666666'
          })
        ],
        alignment: AlignmentType.CENTER,
        spacing: { after: 400 }
      })
    )

    // 处理每条消息
    for (const msg of props.messages) {
      const isUser = msg.sender === 'user'
      
      // 处理图片
      if (msg.imageList && Array.isArray(msg.imageList)) {
        for (const img of msg.imageList) {
          try {
            const imageBuffer = await fetch(img).then(res => res.arrayBuffer())
            const base64 = arrayBufferToBase64(imageBuffer)
            const match = img.match(/^data:image\/(\w+);base64,/)
            const ext = match ? match[1] : 'png'
            const dataUrl = `data:image/${ext};base64,${base64}`
            
            docParagraphs.push(
              new Paragraph({
                alignment: isUser ? AlignmentType.RIGHT : AlignmentType.LEFT,
                children: [
                  new TextRun({
                    text: isUser ? '用户图片：' : `${msg.modelName || 'AI'}图片：`,
                    bold: true,
                    color: isUser ? '2563eb' : '666666'
                  })
                ],
                shading: { fill: isUser ? 'D6EAF8' : 'F2F3F4' },
                spacing: { after: 100 }
              }),
              new Paragraph({
                children: [
                  new ImageRun({
                    data: dataUrl,
                    transformation: { width: 200, height: 120 },
                    type: ext
                  })
                ]
              })
            )
          } catch (imgError) {
            console.error('处理图片失败:', imgError);
            docParagraphs.push(
              new Paragraph({
                children: [
                  new TextRun({
                    text: '[图片加载失败]',
                    color: 'ff4d4f',
                    italics: true
                  })
                ]
              })
            )
          }
        }
      }

      // 处理文本内容
      if (msg.text || msg.content) {
        const html = md.render(msg.text || msg.content || '')
        const tempDiv = document.createElement('div')
        tempDiv.innerHTML = html
        
        const children = parseHtmlToDocx(tempDiv, isUser)
        
        docParagraphs.push(
          new Paragraph({
            alignment: isUser ? AlignmentType.RIGHT : AlignmentType.LEFT,
            children: [
              new TextRun({
                text: isUser ? '用户：' : `${msg.modelName || 'AI'}：`,
                bold: true,
                color: isUser ? '2563eb' : '666666'
              })
            ],
            shading: { fill: isUser ? 'D6EAF8' : 'F2F3F4' },
            spacing: { after: 100 }
          }),
          ...children
        )
      }
    }

    const doc = new Document({ sections: [{ children: docParagraphs }] })
    const blob = await Packer.toBlob(doc)
    const filename = `chat-${props.sessionTitle || props.sessionId || 'session'}.docx`
    saveAs(blob, filename)
    
    message.success('导出成功！')
    emit('export-success', filename)
    
  } catch (error) {
    console.error('导出失败:', error);
    message.error('导出失败，请重试')
    emit('export-error', error)
  } finally {
    exporting.value = false
  }
}

// 工具函数
function arrayBufferToBase64(buffer: ArrayBuffer) {
  let binary = ''
  const bytes = new Uint8Array(buffer)
  const len = bytes.byteLength
  for (let i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i])
  }
  return window.btoa(binary)
}

function parseHtmlToDocx(node: HTMLElement, isUser: boolean) {
  const result: any[] = []
  
  node.childNodes.forEach(child => {
    if (child.nodeType === 3) {
      // 文本节点
      if (child.textContent?.trim()) {
        result.push(new Paragraph({
          children: [new TextRun({ text: child.textContent.trim() })],
          alignment: isUser ? AlignmentType.RIGHT : AlignmentType.LEFT
        }))
      }
    } else if (child.nodeType === 1 && child instanceof Element) {
      const tag = child.tagName.toLowerCase()
      
      switch (tag) {
        case 'pre':
        case 'code':
          result.push(
            new Paragraph({
              children: [
                new TextRun({
                  text: child.textContent || '',
                  font: 'Consolas',
                  color: '008000',
                  shading: { fill: 'F5F5F5' }
                })
              ],
              spacing: { after: 100 }
            })
          )
          break
          
        case 'table':
          const rows: any[] = []
          child.querySelectorAll('tr').forEach((tr: Element) => {
            const cells: any[] = []
            tr.querySelectorAll('th,td').forEach((td: Element) => {
              cells.push(
                new TableCell({
                  children: [new Paragraph(td.textContent || '')],
                  width: { size: 2000, type: WidthType.DXA }
                })
              )
            })
            rows.push(new TableRow({ children: cells }))
          })
          result.push(new Table({ rows }))
          break
          
        case 'ul':
        case 'ol':
          child.querySelectorAll('li').forEach((li: Element) => {
            result.push(
              new Paragraph({
                text: '• ' + li.textContent,
                bullet: { level: 0 },
                alignment: isUser ? AlignmentType.RIGHT : AlignmentType.LEFT
              })
            )
          })
          break
          
        case 'p':
          if (child.textContent?.trim()) {
            result.push(
              new Paragraph({
                children: [new TextRun({ text: child.textContent.trim() })],
                alignment: isUser ? AlignmentType.RIGHT : AlignmentType.LEFT,
                spacing: { after: 100 }
              })
            )
          }
          break
          
        default:
          // 递归处理其他标签
          result.push(...parseHtmlToDocx(child as HTMLElement, isUser))
      }
    }
  })
  
  return result
}
</script>